#include "imageeditgraphicsview.h"

#include "GraphicsItem/abstractpathitem.h"
#include "GraphicsItem/graphicsangleitem.h"
#include "GraphicsItem/graphicsarrowitem.h"
#include "GraphicsItem/graphicscobbangleitem.h"
#include "GraphicsItem/graphicsellipseitem.h"
#include "GraphicsItem/graphicslineitem.h"
#include "GraphicsItem/graphicsrectitem.h"
#include "GraphicsItem/graphicscliprectitem.h"
#include "GraphicsItem/graphicstextmarkdialog.h"
#include "GraphicsItem/graphicstextmarkitem.h"
#include "dicomeditor_global.h"

#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmimgle/dcmimage.h"
#include "dcmtk/dcmdata/dcdatset.h"
#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dcdatset.h"
#include "dcmtk/dcmdata/dcmetinf.h"

#include <QGraphicsPathItem>
#include <QGraphicsPixmapItem>
#include <QGraphicsSimpleTextItem>
#include <QMouseEvent>
#include <QEvent>
#include <QKeyEvent>
#include <QWheelEvent>
#include <QIcon>
#include <QSettings>
#include <QFontDialog>
#include <QMessageBox>
#include <QPainter>
#include <QBitmap>
#include <QMenu>
#include <QFileDialog>

ImageEditGraphicsView::ImageEditGraphicsView(QWidget *parent) :
    scene(new QGraphicsScene(this)),
    pixmapItem(new QGraphicsPixmapItem),
    posValue(new QGraphicsSimpleTextItem),
    windowItem(new QGraphicsSimpleTextItem),
    zoomItem(new QGraphicsSimpleTextItem),
    xScalorItem(new QGraphicsPathItem),
    yScalorItem(new QGraphicsPathItem),
    contextMenu(new QMenu(this)),
    clipRectItem(0),
    currentPathItem(0),
    xSpacing(-1.0),
    ySpacing(-1.0),
    factor(1.0),
    magFactor(2),
    manualZoom(false),
    manualPan(false),
    hflip(0),
    vflip(0),
    rotateAngle(0),
    winCenter(0),
    winWidth(-1),
    rawCenter(0),
    rawWidth(-1),
    ff(0),
    imageIndex(-1),
    QGraphicsView(parent)
{
    QPalette palette = this->palette();
    palette.setColor(QPalette::Base, Qt::black);
    setPalette(palette);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setContextMenuPolicy(Qt::DefaultContextMenu);

    setAlignment(Qt::AlignCenter);
    setScene(scene);
    scene->setSceneRect(-5000, -5000, 10000, 10000);
    pixmapItem->setTransformationMode(Qt::SmoothTransformation);
    pixmapItem->setAcceptHoverEvents(true);
    xScalorItem->setPen(QPen(Qt::green));
    yScalorItem->setPen(QPen(Qt::green));
    posValue->setBrush(Qt::magenta);
    windowItem->setBrush(Qt::green);
    zoomItem->setBrush(Qt::green);
    clipRectItem = new GraphicsClipRectItem(QRectF(0, 0, 2000, 2000), pixmapItem);
    clipRectItem->setPen(QPen(QBrush(Qt::green), 2));
    clipRectItem->setVisible(false);

    subPixmapItem = new QGraphicsPixmapItem(pixmapItem);
    subPixmapItem->setTransformationMode(Qt::SmoothTransformation);
    subPixmapItem->setVisible(false);
    magFactorItem = new QGraphicsSimpleTextItem(subPixmapItem);
    magFactorItem->setBrush(Qt::green);

    double f = QSettings().value(MAGNIFIER_FACTOR).toDouble();
    if (f > 1) magFactor = f;
    QBitmap cur(32, 32), mask(32, 32);
    cur.fill(Qt::color0);
    mask.fill(Qt::color0);
    nullCursor = QCursor(cur, mask);

    scene->addItem(pixmapItem);
    scene->addItem(xScalorItem);
    scene->addItem(yScalorItem);
    scene->addItem(posValue);
    scene->addItem(windowItem);
    scene->addItem(zoomItem);

    setupContextMenu();
}

ImageEditGraphicsView::~ImageEditGraphicsView()
{
    QSettings().setValue(MAGNIFIER_FACTOR, magFactor);
    clear();
}

void ImageEditGraphicsView::setupContextMenu()
{
    rFlagAction = contextMenu->addAction(tr("R Flag"), this, SLOT(addRFlag()));
    lFlagAction = contextMenu->addAction(tr("L Flag"), this, SLOT(addLFlag()));
    contextMenu->addAction(tr("Clip Image"), this, SLOT(clipImage(bool)))->setCheckable(true);
    contextMenu->addAction(tr("Undo Clip"), this, SLOT(undoImage()));
    contextMenu->addAction(tr("Redo Clip"), this, SLOT(redoImage()));
    contextMenu->addAction(tr("Zoom"), this, SLOT(zoomImage()));
    contextMenu->addAction(tr("Pan"), this, SLOT(panImage()));
    contextMenu->addAction(tr("Magnifier"), this, SLOT(magnifier()));
    contextMenu->addAction(tr("Rotate CCW"), this, SLOT(rotateCCW()));
    contextMenu->addAction(tr("Rotate CW"), this, SLOT(rotateCW()));
    contextMenu->addAction(tr("H Flip"), this, SLOT(hFlip()));
    contextMenu->addAction(tr("V Flip"), this, SLOT(vFlip()));
    contextMenu->addAction(tr("Negative"), this, SLOT(inverseImage()));
    contextMenu->addAction(tr("Reset"), this, SLOT(reset()));
    contextMenu->addAction(tr("Clear"), this, SLOT(clear()));
    QMenu *subMenu = contextMenu->addMenu(tr("Measurement"));
    subMenu->addAction(tr("Length"), this, SLOT(drawLenght()));
    subMenu->addAction(tr("Angle"), this, SLOT(drawAngle()));
    subMenu->addAction(tr("Rect"), this, SLOT(drawRectangle()));
    subMenu->addAction(tr("Ellipse"), this, SLOT(drawEllipse()));
    subMenu->addAction(tr("Cobb Angle"), this, SLOT(drawCobbAngle()));
    subMenu->addAction(tr("Arrow"), this, SLOT(drawArrow()));
    subMenu->addAction(tr("Text"), this, SLOT(drawText()));
    subMenu->addAction(tr("Remove Item"), this, SLOT(removeCurrent()));
    contextMenu->addAction(tr("Save As"), this, SLOT(saveFile()));
}

void ImageEditGraphicsView::clear()
{
    qDeleteAll(flagItemList);
    qDeleteAll(itemList);
    qDeleteAll(imageList);
    flagItemList.clear();
    itemList.clear();
    imageList.clear();
    xSpacing = 0;
    ySpacing = 0;
    imageIndex = -1;
    reset();

    windowItem->setText("");
    updateScalors();
}

void ImageEditGraphicsView::saveFile()
{
    if (ff && imageList.size()) {
        QSettings s;
        QString file = s.value(SAVE_FILEPATH, ".").toString();
        file = QFileDialog::getSaveFileName(this, tr("Save Image"), file,
                                            tr("DICOM (*.dcm);;RAW (*.raw)"));
        if (!file.isEmpty()) {
            s.setValue(SAVE_FILEPATH, file);
            saveImage();
            if (file.right(4) == ".dcm") {
                ff->saveFile(file.toLocal8Bit().data(), ff->getMetaInfo()->getOriginalXfer());
            } else if (file.right(4) == ".raw") {
                const ushort *pixelData;
                ulong count;
                if (ff->getDataset() && (ff->getDataset()->findAndGetUint16Array(DCM_PixelData, pixelData, &count) == EC_Normal) && pixelData) {
                    QFile rawFile(file);
                    if (rawFile.open(QIODevice::WriteOnly)) {
                        rawFile.write((char*)pixelData, count*sizeof(ushort));
                        rawFile.close();
                    }
                }
            }
        }
    }
}

bool ImageEditGraphicsView::saveImage()
{
    if (clipRectItem->isVisible()) {
        QMessageBox::StandardButtons b = QMessageBox::warning(this, tr("Clip Image"),
                                                              tr("Image Clipping hasn't finished, apply clipping?"),
                                                              QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel);
        if (QMessageBox::Yes == b) {
            clipImage(false);
        } else if (QMessageBox::No == b){
            clipRectItem->setVisible(false);
        } else return false;
    }

    if (ff && imageList.size()) {
        DicomImage *dcmImage = imageList[imageIndex]->createDicomImage();
        if (dcmImage) {
            const DiPixel *pixel = dcmImage->getInterData();
            if ((pixel->getRepresentation() == EPR_Uint16) ||
                    (pixel->getRepresentation() == EPR_Sint16)) {
                Uint16 *pData = static_cast<Uint16*>(const_cast<void*>(pixel->getData()));
                int width = dcmImage->getWidth();
                int height = dcmImage->getHeight();
                if (hflip && vflip) {
                    rotateAngle += 180;
                    hflip = 0;
                    vflip = 0;
                }
                if (rotateAngle%360 >= 180) {
                    if (hflip) {
                        rotateAngle += 180;
                        hflip = 0;
                        vflip = 1;
                    } else if (vflip) {
                        rotateAngle += 180;
                        vflip = 0;
                        hflip = 1;
                    }
                }
                dcmImage->flipImage(hflip, vflip);
                dcmImage->rotateImage((rotateAngle%360)*((hflip||vflip)?(-1):1));
                int cols = dcmImage->getWidth();
                int rows = dcmImage->getHeight();

                foreach (QGraphicsSimpleTextItem *item, flagItemList) {
                    QImage pixImage(item->boundingRect().size().toSize()*8, QImage::Format_RGB32);
                    pixImage.fill(0xff000000);
                    QPainter painter(&pixImage);
                    QFont font;
                    font.fromString(QSettings().value(IMAGE_FLAG_FONT).toString());
                    font.setPointSize(font.pointSize()*8);
                    painter.setFont(font);
                    QPen pen(Qt::white);
                    pen.setBrush(Qt::white);
                    painter.setPen(pen);
                    painter.drawText(0, painter.fontMetrics().height()-painter.fontMetrics().descent(), item->text());
                    painter.end();
                    //pixImage = pixImage.scaled(pixImage.size()*8, Qt::KeepAspectRatio, Qt::SmoothTransformation);

                    Uint16 pValue = dcmImage->getPhotometricInterpretation()==EPI_Monochrome1?0:65535;
                    QPoint pos = item->pos().toPoint();

                    // Pos transform

                    switch (rotateAngle%360) {
                    case 0:
                        if (hflip) pos.rx() = width - pos.x();
                        else if (vflip) pos.ry() = height - pos.y();
                        break;
                    case 90:
                        if (hflip) {
                            int temp = pos.x();
                            pos.rx() = pos.y();
                            pos.ry() = temp;
                        } else if (vflip) {
                            int temp = pos.x();
                            pos.rx() = height - pos.y();
                            pos.ry() = width - temp;
                        } else {
                            int temp = pos.x();
                            pos.rx() = height - pos.y();
                            pos.ry() = temp;
                        }
                        break;
                    case 180:
                        pos.rx() = width - pos.x();
                        pos.ry() = height - pos.y();
                        break;
                    case 270:
                    {
                        int temp = pos.x();
                        pos.rx() = pos.y();
                        pos.ry() = width - temp;
                    }
                        break;
                    }

                    for (int i = pos.y(); (i < pixImage.height()+pos.y()) && (i < rows); ++i) {
                        for (int j = pos.x(); (j < pixImage.width()+pos.x()) && (j < cols); ++j) {
                            if (pixImage.pixel(j-pos.x(), i-pos.y()) != QRgb(0xff000000))
                                pData[i*cols+j] = pValue;
                        }
                    }
                }
            }

            DcmDataset *dset = ff->getDataset();
            dset->putAndInsertString(DCM_WindowCenter, QString::number(winCenter).toLatin1().data());
            dset->putAndInsertString(DCM_WindowWidth, QString::number(winWidth).toLatin1().data());
            dcmImage->writeImageToDataset(*dset);
            QString spacings = QString("%1\\%2").arg(ySpacing, 0, 'f', 6).arg(xSpacing, 0, 'f', 6);
            dset->putAndInsertString(DCM_ImagerPixelSpacing, spacings.toLatin1().data());
            dset->putAndInsertString(DCM_PixelSpacing, spacings.toLatin1().data());
            delete dcmImage;
            return true;
        }
    }

    return false;
}

bool ImageEditGraphicsView::setFileFormat(DcmFileFormat *dff)
{
    if (dff) {
        const char *value = 0;
        DcmDataset *dset = dff->getDataset();
        dset->findAndGetString(DCM_PixelSpacing, value);
        QStringList spacings = QString::fromLatin1(value).split('\\', QString::SkipEmptyParts);
        if (spacings.size() == 2) {
            ySpacing = spacings.first().toDouble();
            xSpacing = spacings.last().toDouble();
        }

        dset->findAndGetString(DCM_Modality, value);
        if (QString::fromLatin1(value).toUpper() == "MG") {
            dset->findAndGetString(DCM_ProtocolName, value);
            rFlagAction->setText(value);
            lFlagAction->setVisible(false);
            rFlagText = value;
            lFlagText = value;
        } else {
            rFlagAction->setText(tr("R Flag"));
            lFlagAction->setVisible(true);
            rFlagText = "R";
            lFlagText = "L";
        }

        DicomImage *dcmImage = new DicomImage(dff, dset->getOriginalXfer());
        if (dcmImage && (dcmImage->getStatus()==EIS_Normal)) {
            ff = dff;
            int width = dcmImage->getWidth();
            int height = dcmImage->getHeight();
            QRect rect = QRect(width * 0.1, height * 0.1, width * 0.8, height * 0.8);
            dcmImage->setRoiWindow(rect.x(), rect.y(), rect.width(), rect.height());
            dcmImage->getWindow(winCenter, winWidth);

            clipRectItem->setRect(rect);
            rawCenter = winCenter;
            rawWidth = winWidth;

            imageList.prepend(dcmImage);
            imageIndex = 0;

            refreshPixmap();
            updateScalors();
            return true;
        } else {
            delete dcmImage;
            dcmImage = 0;
        }
    }

    return false;
}

void ImageEditGraphicsView::setMagnifierPixmap(const QPointF &itemPos)
{
    double srcWidth = (MAGNIFIER_SIZE) / (magFactor*factor);
    QRect source(itemPos.x()-srcWidth/2, itemPos.y()-srcWidth/2, srcWidth, srcWidth);
    QPixmap subImage(source.size());
    QPainter painter(&subImage);
    painter.drawPixmap(QPoint(0, 0), pixmapItem->pixmap(), source);
    painter.end();
    subPixmapItem->setPos(itemPos.x()-MAGNIFIER_SIZE/(2*factor), itemPos.y()-MAGNIFIER_SIZE/(2*factor));
    subPixmapItem->setPixmap(subImage.scaledToWidth(MAGNIFIER_SIZE, Qt::SmoothTransformation));
    subPixmapItem->setScale(1/factor);
    subPixmapItem->setVisible(true);
    magFactorItem->setText(QString("%1X").arg(magFactor));
    magFactorItem->setPos(subPixmapItem->boundingRect().width() - magFactorItem->boundingRect().width(), 0);
}

void ImageEditGraphicsView::updateScalors()
{
    QPainterPath scalorX, scalorY;
    if ((!imageList.isEmpty()) && (!pixmapItem->pixmap().isNull()) &&
            xSpacing > 0.000001 && ySpacing > 0.000001) {
        double psX = xSpacing;
        double psY = ySpacing;
        if (rotateAngle % 180) {
            psX = ySpacing;
            psY = xSpacing;
        }

        double widthR = 100 / psX;
        double heightR = 100 / psY;

        double stepX = widthR / 10;
        double tickX = stepX / 4;
        double stepY = heightR / 10;
        double tickY = stepY / 4;

        scalorX.moveTo(0, 0);
        scalorX.lineTo(widthR, 0);
        scalorY.moveTo(0, 0);
        scalorY.lineTo(0, heightR);
        for (int i = 0; i <= 10; ++i) {
            scalorX.moveTo(i * stepX, 0);
            scalorX.lineTo(i * stepX, -tickX);
            scalorY.moveTo(0, i * stepY);
            scalorY.lineTo(tickY, i * stepY);
        }
    }

    xScalorItem->setPath(scalorX);
    yScalorItem->setPath(scalorY);
}

void ImageEditGraphicsView::repositionAuxItems()
{
    QPointF sceneTL = mapToScene(rect().topLeft());
    QPointF sceneBR = mapToScene(rect().bottomRight());

    windowItem->setPos(sceneTL.x(), sceneBR.y()-windowItem->boundingRect().height());
    zoomItem->setPos(sceneTL.x(), sceneBR.y()-windowItem->boundingRect().height()*2);
    posValue->setPos(sceneTL.x(), sceneBR.y()-windowItem->boundingRect().height()*3);
    QSizeF xRect = xScalorItem->boundingRect().size()*factor;
    xScalorItem->setPos(sceneTL.x()+((sceneBR.x()-sceneTL.x())-xRect.width())/2,
                        sceneBR.y()-xRect.height());
    QSizeF yRect = yScalorItem->boundingRect().size()*factor;
    yScalorItem->setPos(sceneTL.x()+yRect.width(),
                        sceneTL.y()+((sceneBR.y()-sceneTL.y())-yRect.height())/2);

    if (factor > 2) {
        xScalorItem->setVisible(false);
        yScalorItem->setVisible(false);
    } else {
        xScalorItem->setVisible(true);
        yScalorItem->setVisible(true);
    }
}

void ImageEditGraphicsView::refreshPixmap()
{
    pixmapItem->setPixmap(getPixmap());
    resizePixmapItem();
    repositionAuxItems();
    windowItem->setText(tr("WL:%1 WW:%2").arg(int(winCenter)).arg(int(winWidth)));
}

void ImageEditGraphicsView::resizePixmapItem()
{
    QRectF pixmapRect = pixmapItem->boundingRect();
    QRectF viewRect = this->rect();

    if ((!imageList.isEmpty()) && (!pixmapItem->pixmap().isNull())) {
        if (!manualZoom) {
            if (pixmapRect.width()*viewRect.height() < pixmapRect.height()*viewRect.width())
                factor = viewRect.height()/pixmapRect.height();
            else
                factor = viewRect.width()/pixmapRect.width();
        }

        pixmapItem->setScale(factor);
        pixmapItem->setTransformOriginPoint(pixmapItem->boundingRect().center());
        if (!manualPan) centerOn(pixmapItem);
        zoomItem->setText(tr("Zoom: %1%").arg(factor*100, 0, 'f', 2));
        foreach (QGraphicsSimpleTextItem *item, flagItemList) {
            item->setScale(factor*8);
        }

        xScalorItem->setScale(factor);
        yScalorItem->setScale(factor);
        QPen pen = xScalorItem->pen();
        pen.setWidthF(1/factor);
        xScalorItem->setPen(pen);
        yScalorItem->setPen(pen);
        pen = clipRectItem->pen();
        pen.setWidthF(1/factor);
        clipRectItem->setPen(pen);

        foreach (QGraphicsItem* item, itemList) {
            static_cast<AbstractPathItem*>(item)->setZoomFactor(factor);
        }
    } else {
        zoomItem->setText("");
    }
}

QPixmap ImageEditGraphicsView::getPixmap()
{
    QPixmap pixmap;

    if (imageIndex >= 0 && imageIndex < imageList.size())
        dcm2pixmap(pixmap, imageList[imageIndex], winCenter, winWidth);
    return pixmap;
}

bool ImageEditGraphicsView::dcm2pixmap(QPixmap &pixmap, DicomImage *image, double center, double width)
{
    if (image) {
        image->setWindow(center, width);
        int w, h;
        w = image->getWidth();
        h = image->getHeight();
        void *pDIB = 0;
        image->createWindowsDIB(pDIB, 0, 0, 32, 0, 1);
        if (pDIB) {
            QImage img((uchar*)pDIB, w, h, QImage::Format_RGB32, &ImageEditGraphicsView::freeBuffer, pDIB);
            pixmap = QPixmap::fromImage(img);
            return !pixmap.isNull();
        }
    }

    return false;
}

void ImageEditGraphicsView::mousePressEvent(QMouseEvent *event)
{
    QPointF sp = mapToScene(event->pos());
    QPointF ip = pixmapItem->mapFromScene(sp);
    prevMousePos = event->pos();
    prevPressedPos = event->pos();

    if (event->button() == Qt::RightButton) {
        switch(leftButton.state) {
        case Drawing:
            if (currentPathItem) {
                currentPathItem->ungrabMouse();
                delete currentPathItem;
                currentPathItem = 0;
            }
            break;
        case AddFlag:
            flagItemList.last()->setPos(ip);
            flagItemList.last()->ungrabMouse();
            break;
        }
    } else if (event->button() == Qt::LeftButton) {
        setDragMode(QGraphicsView::NoDrag);
        switch (leftButton.state) {
        case None:
            setDragMode(QGraphicsView::RubberBandDrag);
            break;
        case Drawing:
            if (currentPathItem == NULL) {
                switch (leftButton.type) {
                case DrawLine:
                    currentPathItem = new GraphicsLineItem(pixmapItem);
                    break;
                case DrawAngle:
                    currentPathItem = new GraphicsAngleItem(pixmapItem);
                    break;
                case DrawCobbAngle:
                    currentPathItem = new GraphicsCobbAngleItem(pixmapItem);
                    break;
                case DrawRect:
                    currentPathItem = new GraphicsRectItem(pixmapItem);
                    break;
                case DrawEllipse:
                    currentPathItem = new GraphicsEllipseItem(pixmapItem);
                    break;
                case DrawTextMark:
                    break;
                case DrawArrow:
                    currentPathItem = new GraphicsArrowItem(pixmapItem);
                    break;
                }
                if (currentPathItem) {
                    currentPathItem->setPos(ip);
                    currentPathItem->setZoomFactor(factor);
                    currentPathItem->grabMouse();
                    currentPathItem->setPixelSpacing(xSpacing, ySpacing);
                }
            } else {
                if (leftButton.type == DrawTextMark) {
                    currentPathItem->setPos(ip);
                    currentPathItem->ungrabMouse();
                    itemList.append(currentPathItem);
                    currentPathItem = 0;
                    leftButton.state = None;
                } else {
                    currentPathItem->nextStage();
                    AbstractPathItem::Stage stage = currentPathItem->getCurrentStage();
                    if (stage == AbstractPathItem::Final) {
                        currentPathItem->ungrabMouse();
                        itemList.append(currentPathItem);
                        if (imageList.size()) currentPathItem->recalPixInfo(imageList.at(imageIndex));
                        currentPathItem = 0;
                    }
                }
            }
            break;
        case Zoom:
            manualZoom = true;
            break;
        case Pan:
            setCursor(Qt::ClosedHandCursor);
            manualPan = true;
            break;
        case Magnifier:
            setCursor(nullCursor);
            setMagnifierPixmap(ip);
            break;
        case AddFlag:
            flagItemList.last()->setPos(ip);
            flagItemList.last()->ungrabMouse();
            leftButton.state = None;
            break;
        }
    }

    QGraphicsView::mousePressEvent(event);
}

void ImageEditGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    QPointF scenePoint = mapToScene(event->pos());
    QPointF itemPoint = pixmapItem->mapFromScene(scenePoint);

    if (pixmapItem->contains(itemPoint)) {
        QPoint pos = itemPoint.toPoint();

        EP_Representation r;
        uint value = getPixelValue(pos.x(), pos.y(), r);
        switch (r) {
        case EPR_Sint8:
            posValue->setText(QString("X: %1 Y: %2 Val: %3").arg(pos.x()).arg(pos.y())
                                   .arg((qint8)value));
            break;
        case EPR_Sint16:
            posValue->setText(QString("X: %1 Y: %2 Val: %3").arg(pos.x()).arg(pos.y())
                                   .arg((qint16)value));
            break;
        case EPR_Sint32:
            posValue->setText(QString("X: %1 Y: %2 Val: %3").arg(pos.x()).arg(pos.y())
                                   .arg((qint32)value));
            break;
        case EPR_Uint8:
            posValue->setText(QString("X: %1 Y: %2 Val: %3").arg(pos.x()).arg(pos.y())
                                   .arg(uchar(value)));
            break;
        case EPR_Uint16:
            posValue->setText(QString("X: %1 Y: %2 Val: %3").arg(pos.x()).arg(pos.y())
                                   .arg(ushort(value)));
            break;
        case EPR_Uint32:
            posValue->setText(QString("X: %1 Y: %2 Val: %3").arg(pos.x()).arg(pos.y())
                                   .arg(value));
            break;
        default:
            posValue->setText(QString());
            break;
        }
    } else posValue->setText(QString());

    if (event->buttons() & Qt::RightButton) {
        setCursor(Qt::ArrowCursor);
        setDragMode(QGraphicsView::NoDrag);
        QPoint delta = event->pos() - prevMousePos;
        prevMousePos = event->pos();
        winCenter -= delta.y()*32;
        winWidth += delta.x()*32;
        if (winWidth < 0) winWidth = 1;
        pixmapItem->setPixmap(getPixmap());
        windowItem->setText(tr("WL:%1 WW:%2").arg(int(winCenter)).arg(int(winWidth)));
    } else {
        switch (leftButton.state) {
        case Drawing:
            setCursor(Qt::CrossCursor);
            if (currentPathItem) {
                if (leftButton.type == DrawTextMark) {
                    currentPathItem->setPos(itemPoint);
                } else {
                    currentPathItem->setActivePoint(currentPathItem->mapFromParent(itemPoint));
                    scene->update();
                }
            }
            break;
        case Zoom:
            setCursor(Qt::SizeAllCursor);
            if (event->buttons() & Qt::LeftButton) {
                scene->clearSelection();
                if (scene->mouseGrabberItem()) scene->mouseGrabberItem()->ungrabMouse();
                int delta = prevMousePos.y() - event->pos().y();
                prevMousePos = event->pos();
                if (delta > 0) factor /=(1+delta/60.0);
                else factor *= (1-delta/60.0);
                if (factor > 10.0) factor = 10.0;
                if (factor < 0.05) factor = 0.05;
                resizePixmapItem();
                repositionAuxItems();
            }
            break;
        case Pan:
            if ((event->buttons() & Qt::LeftButton)) {
                setCursor(Qt::ClosedHandCursor);
                scene->clearSelection();
                if (scene->mouseGrabberItem()) scene->mouseGrabberItem()->ungrabMouse();
                QPoint deltaPos = event->pos() - prevMousePos;
                prevMousePos = event->pos();
                pixmapItem->setPos(pixmapItem->pos()+deltaPos);
            } else setCursor(Qt::OpenHandCursor);
            break;
        case Magnifier:
            if (event->buttons() & Qt::LeftButton) {
                setCursor(nullCursor);
                scene->clearSelection();
                if (scene->mouseGrabberItem()) scene->mouseGrabberItem()->ungrabMouse();
                setMagnifierPixmap(itemPoint);
            } else {
                setCursor(Qt::SizeAllCursor);
            }
            break;
        case AddFlag:
            flagItemList.last()->setPos(itemPoint);
            break;
        }
    }

    QGraphicsView::mouseMoveEvent(event);
}

void ImageEditGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        switch (leftButton.state) {
        case Drawing:
            /* never goes here ?
            if ((leftButton.type == DrawCurve || leftButton.type == DrawTextMark) && currentPathItem) {
                itemList.append(currentPathItem);
                currentPathItem->ungrabMouse();
                currentPathItem->nextStage();
                currentPathItem = 0;
            }
            */
            break;
        case Pan:
            setCursor(Qt::OpenHandCursor);
            break;
        case Magnifier:
            setCursor(Qt::SizeAllCursor);
            subPixmapItem->setVisible(false);
            break;
        case None:
            if (imageList.size() && scene->selectedItems().size()==0) {
                if (rubberBandRect().isValid()) {
                    QRectF selectedRect = pixmapItem->mapFromScene(mapToScene(rubberBandRect())).boundingRect();
                    imageList[imageIndex]->setRoiWindow(selectedRect.x(), selectedRect.y(),
                                           selectedRect.width(), selectedRect.height());
                    /*
                    QPointF topleftPoint = pixmapItem->mapFromScene(mapToScene(selectedRect.topLeft()));
                    QPointF bottomrightPoint = pixmapItem->mapFromScene(mapToScene(selectedRect.bottomRight()));

                    imageList[imageIndex]->setRoiWindow(topleftPoint.x(), topleftPoint.y(),
                                           bottomrightPoint.x()-topleftPoint.x(),
                                           bottomrightPoint.y()-topleftPoint.y());
                                           */
                    imageList[imageIndex]->getWindow(winCenter, winWidth);
                    windowItem->setText(tr("WL:%1 WW:%2").arg(int(winCenter)).arg(int(winWidth)));
                    pixmapItem->setPixmap(getPixmap());
                }

                foreach (AbstractPathItem *it, itemList) {
                    if (!it->pixInfoUpdated()) {
                        it->recalPixInfo(imageList.at(imageIndex));
                        scene->update();
                    }
                }
            }
            break;
        }
    }

    QGraphicsView::mouseReleaseEvent(event);
}

void ImageEditGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
{
    if (itemAt(event->pos()) == clipRectItem) {
        clipImage(false);
        emit imageClipped(false);
    }
}

void ImageEditGraphicsView::wheelEvent(QWheelEvent *event)
{
    QPoint delta = event->angleDelta();
    if ((event->buttons() & Qt::LeftButton) && (leftButton.state == Magnifier)) {
        if (delta.y() > 0) magFactor += 1;
        else if (magFactor >= 3) magFactor -= 1;

        QPointF sp = mapToScene(event->pos());
        setMagnifierPixmap(pixmapItem->mapFromScene(sp));
    } else {
        manualZoom = true;
        if (delta.y() > 0) factor *= (1+delta.y()/600.0);
        else factor /= (1-delta.y()/600.0);
        if (factor > 32.0) factor = 32.0;
        if (factor < 0.05) factor = 0.05;
        resizePixmapItem();
        repositionAuxItems();
    }
}

void ImageEditGraphicsView::leaveEvent(QEvent *event)
{
    posValue->setText("");
    QGraphicsView::leaveEvent(event);
}

void ImageEditGraphicsView::keyPressEvent(QKeyEvent *event)
{
    QPointF pos = pixmapItem->pos();
    if (event->key() == Qt::Key_Delete) {
        removeCurrent();
    } else if (event->key() == Qt::Key_Up) {
        pos.ry() -= 4;
        manualPan = true;
    } else if (event->key() == Qt::Key_Down) {
        pos.ry() += 4;
        manualPan = true;
    } else if (event->key() == Qt::Key_Left) {
        pos.rx() -= 4;
        manualPan = true;
    } else if (event->key() == Qt::Key_Right) {
        pos.rx() += 4;
        manualPan = true;
    } else if (event->key() == Qt::Key_Escape) {
        setNone();
    } else {
        QGraphicsView::keyPressEvent(event);
    }
    pixmapItem->setPos(pos);
}

void ImageEditGraphicsView::resizeEvent(QResizeEvent *event)
{
    QGraphicsView::resizeEvent(event);
    resizePixmapItem();
    repositionAuxItems();
}

void ImageEditGraphicsView::contextMenuEvent(QContextMenuEvent *event)
{
    if (event->pos() == prevPressedPos) {
        if (leftButton.state != None) {
            leftButton.state = None;
            setCursor(Qt::ArrowCursor);
            setDragMode(QGraphicsView::NoDrag);
        } else {
            contextMenu->popup(event->globalPos());
        }
    }
}

void ImageEditGraphicsView::addRFlag()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(pixmapItem);
        item->setBrush(Qt::white);
        item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable |
                       QGraphicsItem::ItemIgnoresTransformations);
        item->setScale(factor*8);
        QFont font;
        font.fromString(QSettings().value(IMAGE_FLAG_FONT).toString());
        item->setFont(font);
        item->setText(rFlagText);
        item->grabMouse();
        leftButton.state = AddFlag;
        flagItemList.append(item);
        setCursor(Qt::ArrowCursor);
    }
}

void ImageEditGraphicsView::addLFlag()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(pixmapItem);
        item->setBrush(Qt::white);
        item->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsSelectable |
                       QGraphicsItem::ItemIgnoresTransformations);
        item->setScale(factor*8);
        QFont font;
        font.fromString(QSettings().value(IMAGE_FLAG_FONT).toString());
        item->setFont(font);
        item->setText(lFlagText);
        item->grabMouse();
        leftButton.state = AddFlag;
        flagItemList.append(item);
        setCursor(Qt::ArrowCursor);
    }
}

void ImageEditGraphicsView::onFlagFont()
{
    QSettings settings;
    QFont font;
    font.fromString(settings.value(IMAGE_FLAG_FONT).toString());
    bool ok;
    font = QFontDialog::getFont(&ok, font, this);
    if (ok) {
        settings.setValue(IMAGE_FLAG_FONT, font.toString());
    }
}

void ImageEditGraphicsView::setNone()
{
    if (currentPathItem) {
        currentPathItem->ungrabMouse();
        delete currentPathItem;
        currentPathItem = 0;
    }
    leftButton.state = None;
    setCursor(Qt::ArrowCursor);
}

void ImageEditGraphicsView::clipImage(bool checked)
{
    if (imageList.size()) {
        if (!checked) {
            QRectF clipRect = clipRectItem->getClipRect();
            if (!clipRectFirst.isValid()) {
                clipRectFirst = clipRect;
            }
            Uint16 value = imageList[imageIndex]->getPhotometricInterpretation()==EPI_Monochrome1?65535:0;
            DicomImage *dcmImage = imageList[imageIndex]->createClippedImage(
                        clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height(),
                        value);
            if (dcmImage) {
                imageList.insert(imageIndex, dcmImage);
                pixmapItem->setPixmap(getPixmap());
                resizePixmapItem();
                repositionAuxItems();

            }

            // adjust item position
            foreach (QGraphicsItem *item, flagItemList) {
                item->setPos(item->pos() - clipRect.topLeft());
            }
            foreach (QGraphicsItem *item, itemList) {
                item->setPos(item->pos() - clipRect.topLeft());
            }
        } else {
            int width = imageList.at(imageIndex)->getWidth();
            int height = imageList.at(imageIndex)->getHeight();
            clipRectItem->setRect(QRect(width*0.1, height*0.1, width*0.8, height*0.8));
        }
        clipRectItem->setVisible(checked);
    }
}

void ImageEditGraphicsView::undoImage()
{
    if (imageIndex < imageList.size()-1) {
        imageIndex++;
        pixmapItem->setPixmap(getPixmap());
        resizePixmapItem();
        repositionAuxItems();
    }
}

void ImageEditGraphicsView::redoImage()
{
    if (imageIndex > 0) {
        imageIndex--;
        pixmapItem->setPixmap(getPixmap());
        resizePixmapItem();
        repositionAuxItems();
    }
}

void ImageEditGraphicsView::inverseImage()
{
    if (imageList.size()) {
        DicomImage *dcmImage = imageList[imageIndex];
        dcmImage->setPolarity(dcmImage->getPolarity()==EPP_Normal?EPP_Reverse:EPP_Normal);
        pixmapItem->setPixmap(getPixmap());
    }
}

void ImageEditGraphicsView::rotateCCW()
{
    rotateAngle += 270;
    //rotateAngle %= 360;

    QRectF pRect = pixmapItem->boundingRect();
    pixmapItem->setTransformOriginPoint(pRect.width()/2, pRect.height()/2);
    pixmapItem->setRotation(rotateAngle);
    //pixmapItem->setTransform(QTransform(0, 1, -1, 0, pRect.width()/2, pRect.height()/2), true);
    if (!manualPan) centerOn(pixmapItem);
    updateScalors();
    repositionAuxItems();
    clipRectItem->reverseCornerCursor();
    clipRectItem->reverseMiddleCursor();
}

void ImageEditGraphicsView::rotateCW()
{
    rotateAngle += 90;
    //rotateAngle %= 360;

    QRectF pRect = pixmapItem->boundingRect();
    pixmapItem->setTransformOriginPoint(pRect.width()/2, pRect.height()/2);
    pixmapItem->setRotation(rotateAngle);
    //pixmapItem->setTransform(QTransform(0, -1, 1, 0, pRect.width()/2, pRect.height()/2), true);
    if (!manualPan) centerOn(pixmapItem);
    updateScalors();
    repositionAuxItems();
    clipRectItem->reverseCornerCursor();
    clipRectItem->reverseMiddleCursor();
}

void ImageEditGraphicsView::zoomImage()
{
    if (scene->mouseGrabberItem()==0) {
        scene->clearSelection();
        leftButton.state = Zoom;
        setCursor(Qt::SizeAllCursor);
    }
}

void ImageEditGraphicsView::magnifier()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        scene->clearSelection();
        leftButton.state = Magnifier;
        setCursor(Qt::SizeAllCursor);
    }
}

void ImageEditGraphicsView::hFlip()
{
    QRectF pRect = pixmapItem->boundingRect();
    pixmapItem->setTransformOriginPoint(pRect.width()/2, pRect.height()/2);
    pixmapItem->setTransform(QTransform(-1, 0, 0, 1, pRect.width(), 0), true);
    if (!manualPan) centerOn(pixmapItem);
    repositionAuxItems();
    hflip = !hflip;
    clipRectItem->reverseCornerCursor();
}

void ImageEditGraphicsView::vFlip()
{
    QRectF pRect = pixmapItem->boundingRect();
    pixmapItem->setTransformOriginPoint(pRect.width()/2, pRect.height()/2);
    pixmapItem->setTransform(QTransform(1, 0, 0, -1, 0, pRect.height()), true);
    if (!manualPan) centerOn(pixmapItem);
    repositionAuxItems();
    vflip = !vflip;
    clipRectItem->reverseCornerCursor();
}

void ImageEditGraphicsView::panImage()
{
    if (scene->mouseGrabberItem()==0) {
        scene->clearSelection();
        leftButton.state = Pan;
        setCursor(Qt::OpenHandCursor);
        manualPan = true;
    }
}

void ImageEditGraphicsView::drawLenght()
{
    if (scene->mouseGrabberItem()==0) {
        leftButton.state = Drawing;
        leftButton.type = DrawLine;
        setCursor(Qt::CrossCursor);
    }
}

void ImageEditGraphicsView::drawAngle()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        leftButton.state = Drawing;
        leftButton.type = DrawAngle;
        setCursor(Qt::CrossCursor);
    }
}

void ImageEditGraphicsView::drawCobbAngle()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        leftButton.state = Drawing;
        leftButton.type = DrawCobbAngle;
        setCursor(Qt::CrossCursor);
    }
}

void ImageEditGraphicsView::drawEllipse()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        leftButton.state = Drawing;
        leftButton.type = DrawEllipse;
        setCursor(Qt::CrossCursor);
    }
}

void ImageEditGraphicsView::drawRectangle()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        leftButton.state = Drawing;
        leftButton.type = DrawRect;
        setCursor(Qt::CrossCursor);
    }
}

void ImageEditGraphicsView::drawArrow()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        leftButton.state = Drawing;
        leftButton.type = DrawArrow;
        setCursor(Qt::CrossCursor);
    }
}

void ImageEditGraphicsView::drawText()
{
    if (scene->mouseGrabberItem()==0 && imageList.size()) {
        leftButton.state = Drawing;
        leftButton.type = DrawTextMark;
        GraphicsTextMarkDialog dialog(this);
        if ((dialog.exec() == QDialog::Accepted) &&
                (!dialog.getText().isEmpty())) {
            GraphicsTextMarkItem *item = new GraphicsTextMarkItem(pixmapItem);
            item->setLabelItemText(dialog.getText());
            item->grabMouse();
            currentPathItem = item;
        }
    }
}

void ImageEditGraphicsView::removeCurrent()
{
    if (currentPathItem) {
        currentPathItem->ungrabMouse();
        delete currentPathItem;
        currentPathItem = 0;
    }

    QList<QGraphicsItem*> items = scene->selectedItems();
    foreach (QGraphicsItem *item, items) {
        if ((item->parentItem() == pixmapItem) ||
                ((item = item->parentItem()) && (item->parentItem() == pixmapItem))) {
            //scene->removeItem(item);
            if (itemList.contains(static_cast<AbstractPathItem*>(item)))
                itemList.removeOne(static_cast<AbstractPathItem*>(item));
            else flagItemList.removeOne(static_cast<QGraphicsSimpleTextItem*>(item));
            delete item;
        }
    }
}

void ImageEditGraphicsView::reset()
{
    if (imageList.count() && imageList[imageIndex]) {
        winCenter = rawCenter;
        winWidth = rawWidth;
    }
    pixmapItem->setRotation(0);
    pixmapItem->setPos(0, 0);
    rotateAngle = 0;
    pixmapItem->resetTransform();
    hflip = 0;
    vflip = 0;
    manualZoom = false;
    manualPan = false;
    refreshPixmap();
}

uint ImageEditGraphicsView::getPixelValue(long x, long y, EP_Representation &r) const
{
    if (imageList.size()) {
        DicomImage *dcmImage = imageList[imageIndex];
        const DiPixel* pixel = dcmImage->getInterData();
        if (pixel && (x < (long)dcmImage->getWidth()) && (x >= 0)
                && (y < (long)dcmImage->getHeight()) && (y >= 0)) {
            r = pixel->getRepresentation();
            switch (r) {
            case EPR_Sint8:
            case EPR_Uint8:
                return *((char*)(pixel->getData()) + (y * dcmImage->getWidth() + x));
            case EPR_Sint16:
            case EPR_Uint16:
                return *((short*)(pixel->getData()) + (y * dcmImage->getWidth() + x));
            case EPR_Sint32:
            case EPR_Uint32:
                return *((int*)(pixel->getData()) + (y * dcmImage->getWidth() + x));
            }
        }
    }
    r = (EP_Representation)-1;
    return 0;
}
